/*************************************************************************
 Copyright (C) Unpublished Unis Software, Inc. All rights reserved.
 Unis Software, Inc., Confidential and Proprietary.

 This software is subject to copyright protection
 under the laws of the Public of China and other countries.

 Unless otherwise explicitly stated, this software is provided
 by Unis "AS IS".
 *************************************************************************/
package com.unis.common.util;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.unis.common.util.SpyUtil.TableMetaData;

import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;

/**
 * @author CSJ (email:raulcsj@163.com)
 * @since 2012-11-26
 */
public final class CodeGenUtil {
    private static Logger logger = LoggerFactory.getLogger(CodeGenUtil.class);
    /****************************************
     * 默认FTL模板路径
     ****************************************/
    private static final String TEMPLATE_PATH = "com/unis/model/template/ftl";
    private static final List<String> TYPES = new ArrayList<String>();

    /****************************************
     * FreeMarker 配置器 只加载一次
     ****************************************/
    private static Configuration CFG;

    private static File templates = null;

    static {
        TYPES.add(0, "Model.ftl");
        TYPES.add(1, "Sql.ftl");
        TYPES.add(2, "Service.ftl");
        TYPES.add(3, "ServiceImpl.ftl");
        TYPES.add(4, "Controller.ftl");
        TYPES.add(5, "View.ftl");
        CFG = new Configuration();
        String clsPath = CodeGenUtil.class.getClassLoader().getResource("").getPath();
        templates = new File(clsPath + TEMPLATE_PATH);
        try {
            CFG.setDirectoryForTemplateLoading(templates);
        } catch (IOException e) {
            logger.error(e.getMessage());
        }
        CFG.setObjectWrapper(new DefaultObjectWrapper());
        CFG.setLocale(Locale.CHINA);
        CFG.setDefaultEncoding("UTF-8");
    }

    private CodeGenUtil() {}

    /****************************************
     * 启动代码生成模板
     * 
     * @param args
     * @throws Exception
     ****************************************/
    private static void process(String tmpName, String output, Map<String, Object> dataMap) throws Exception {
        String module = dataMap.get("module").toString();
        String classname = dataMap.get("classname").toString();
        StringBuilder builder = new StringBuilder();
        Template template = CFG.getTemplate(tmpName);
        template.setEncoding("UTF-8");
        builder.append(output).append("/").append("com/unis/");
        int type = TYPES.indexOf(tmpName);
        switch (type) {
        case 1:
            builder.append("model/sql/").append(module).append("/");
            FileUtils.forceMkdir(new File(builder.toString()));
            builder.append(classname).append(".xml");
            break;
        case 2:
            builder.append("service/").append(module).append("/");
            FileUtils.forceMkdir(new File(builder.toString()));
            builder.append(classname).append("Service").append(".java");
            break;
        case 3:
            builder.append("service/").append(module).append("/");
            FileUtils.forceMkdir(new File(builder.toString()));
            builder.append(classname).append("ServiceImpl").append(".java");
            break;
        case 4:
            builder.append("web/").append(module).append("/");
            FileUtils.forceMkdir(new File(builder.toString()));
            builder.append(classname).append("Controller").append(".java");
            break;
        case 5:
            builder.replace(builder.indexOf("com/unis/"), builder.length(), "");
            builder.append("view/").append(module).append("/");
            FileUtils.forceMkdir(new File(builder.toString()));
            builder.append(classname.toLowerCase()).append("List").append(".jsp");
            break;
        default:
            builder.append("model/").append(module).append("/");
            FileUtils.forceMkdir(new File(builder.toString()));
            builder.append(classname).append(".java");
            break;
        }

        Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(builder.toString())),
                "UTF-8"));
        template.process(dataMap, out);
        out.flush();
        out.close();
    }

    /****************************************
     * @param args 0: module 模块名 1: classname 类名 2: email 3: output
     * @throws IOException
     * @throws TemplateException
     ****************************************/
    public static void main(String[] args) throws Exception {
        if (args.length != 5) {
            throw new RuntimeException("Invalid input params");
        }
        String user = System.getProperty("user.name");
        String createDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        Map<String, Object> dataMap = new HashMap<String, Object>();
        dataMap.put("user", user);
        dataMap.put("createDate", createDate);
        String module = args[0];
        String classname = args[1];
        String email = args[2];
        String output = args[3];
        String tableName = args[4].toUpperCase();
        dataMap.put("module", module);
        dataMap.put("classname", classname);
        dataMap.put("email", email);
        TableMetaData tableMetaData = SpyUtil.spyDB(tableName);
        dataMap.put("tableMetaData", tableMetaData);
        File[] files = templates.listFiles();
        for (File file : files) {
            process(file.getName(), output, dataMap);
        }
    }
}
